<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<!-- base href="http://www.codeslinger.co.uk/pages/projects/gameboy/lcd.html" --></head><body><div style="background:#fff;border:1px solid #999;margin:-1px -1px 0;padding:0;"><div style="background:#ddd;border:1px solid #999;color:#000;font:13px arial,sans-serif;font-weight:normal;margin:12px;padding:8px;text-align:left">Esta es la versión en caché de <a href="http://www.codeslinger.co.uk/pages/projects/gameboy/lcd.html" style="text-decoration: underline; color: rgb(0, 0, 204);">http://www.codeslinger.co.uk/pages/projects/gameboy/lcd.html</a>
 de Google. Se trata de una captura de pantalla de la página tal como 
esta se mostraba el 15 Jun 2011 16:18:40 GMT. Es posible que la <a href="http://www.codeslinger.co.uk/pages/projects/gameboy/lcd.html" style="text-decoration: underline; color: rgb(0, 0, 204);">página</a> haya sufrido modificaciones durante este tiempo. <a href="http://www.google.com/intl/es/help/features_list.html#cached" style="text-decoration: underline; color: rgb(0, 0, 204);">Más información</a><br><br><div style="float:right"><a href="http://webcache.googleusercontent.com/search?q=cache:rKrHQjN7ekcJ:www.codeslinger.co.uk/pages/projects/gameboy/lcd.html+codeslinger+gameboy+lcd&amp;hl=es&amp;gl=ar&amp;strip=1" style="text-decoration: underline; color: rgb(0, 0, 204);">Versión de solo texto</a></div>
<div>Se han resaltado estos términos de búsqueda: <span style="background:#ffff66;color:black;font-weight:bold">codeslinger</span>&nbsp;<span style="background:#a0ffff;color:black;font-weight:bold">gameboy</span>&nbsp;<span style="background:#99ff99;color:black;font-weight:bold">lcd</span>&nbsp;&nbsp;</div></div></div><div style="position:relative">



<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="description" content="_Emulation Programming_">
<meta name="keywords" content="_Emulation,Chip8,Gameboy,NES,SNES,Genesis,Master,System,Mega,Drive_">
<meta name="author" content="CodeSlinger /">
<link rel="stylesheet" type="text/css" href="7%20LCD_files/css.css" media="screen,projection" title="CodeSlinger (screen)">
<link rel="stylesheet" type="text/css" href="7%20LCD_files/print.css" media="print">
<title>codeslinger.co.uk</title>



<div>
<br><br>
</div>

<div id="container">
<div id="logo">
<h1><a href="http://www.codeslinger.co.uk/index.html"><b style="color:black;background-color:#ffff66">codeslinger</b>.co.uk</a></h1>
</div>

<div id="navitabs">
<h2 class="hide">Site menu:</h2>
<a class="navitab" href="http://www.codeslinger.co.uk/index.php">Home</a><span class="hide"> | </span>
<a class="navitab" href="http://www.codeslinger.co.uk/pages/basics.html">Basics</a><span class="hide"> | </span>
<a class="navitab" href="http://www.codeslinger.co.uk/pages/projects/zuko.html">Zuko</a><span class="hide"> | </span>
<a class="navitab" href="http://www.codeslinger.co.uk/pages/projects/megadrive.html">Mega Drive/Genesis</a><span class="hide"> | </span>
<a class="navitab" href="http://www.codeslinger.co.uk/pages/projects/mastersystem.html">Master System</a><span class="hide"> | </span>
<a class="activenavitab" href="http://www.codeslinger.co.uk/pages/projects/gameboy.html"><b style="color:black;background-color:#a0ffff">Gameboy</b></a><span class="hide"> | </span>
<a class="navitab" href="http://www.codeslinger.co.uk/pages/projects/chip8.html">Chip8</a><span class="hide"> | </span>
<a class="navitab" href="http://www.codeslinger.co.uk/pages/blog/index.html">Blog</a><span class="hide"> | </span>
</div>
	
<div id="desc">
<h2><b style="color:black;background-color:#ffff66">codeslinger</b>.co.uk</h2>
<p> <b style="color:black;background-color:#a0ffff">Gameboy</b> - <b style="color:black;background-color:#99ff99">LCD</b>.</p>

</div>

<div id="main">

<h3><b>Scanlines:</b></h3>
<p>

The screen resolution is 160x144 meaning there are 144 visible scanlines. The <b style="color:black;background-color:#a0ffff">Gameboy</b>
 draws each scanline one at a time starting from 0 to 153, this means
there are 144 visible scanlines and 8 invisible scanlines. When the 
current scanline is between 144 and 153 this is the vertical blank 
period. The current scanline
is stored in register address 0xFF44. The pandocs tell us
that it takes 456 cpu clock cycles to draw one scanline and move onto 
the next, so we will need a counter to know when to move onto the next 
line, we'll call
this m_ScanlineCounter. Just like the timer and divider registers we can
 control the scanline counter by subtracting its value by the amount of 
clock cycles the last
opcode took to exectue. If we look at our main emulator update loop that
 we emulated in the <a href="http://www.codeslinger.co.uk/pages/projects/gameboy/beginning.html">Getting Started</a>
 chapter you can see that the
UpdateGraphics function gets passed the amount of cycles the last opcode
 took so we can accurately keep the graphics in sync with the cpu. This 
is how the UpdateGraphics
function is emulated:

</p><p class="code">

void Emulator::UpdateGraphics(int cycles)<br>
{<br>
&nbsp;&nbsp; SetLCDStatus( ) ; <br><br>

&nbsp;&nbsp; if (IsLCDEnabled())<br>
&nbsp;&nbsp;&nbsp;&nbsp; m_ScalineCounter -= cycles ;<br>
&nbsp;&nbsp; else <br>
&nbsp;&nbsp;&nbsp;&nbsp; return ; <br><br>

&nbsp;&nbsp; if (m_ScalineCounter &lt;= 0)<br>
&nbsp;&nbsp; {<br>

&nbsp;&nbsp;&nbsp;&nbsp; // time to move onto next scanline<br>
&nbsp;&nbsp;&nbsp;&nbsp; m_Rom[0xFF44]++; <br>
&nbsp;&nbsp;&nbsp;&nbsp; BYTE currentline = ReadMemory(0xFF44) ;<br><br>

&nbsp;&nbsp;&nbsp;&nbsp; m_ScalineCounter = 456 ;<br><br>

&nbsp;&nbsp;&nbsp;&nbsp; // we have entered vertical blank period<br>
&nbsp;&nbsp;&nbsp;&nbsp; if (currentline == 144)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RequestInterupt(0) ;<br><br>

&nbsp;&nbsp;&nbsp;&nbsp;  // if gone past scanline 153 reset to 0<br>
&nbsp;&nbsp;&nbsp;&nbsp;  else if (currentline &gt; 153)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_Rom[0xFF44]=0<br><br>

&nbsp;&nbsp;&nbsp;&nbsp; // draw the current scanline <br>
&nbsp;&nbsp;&nbsp;&nbsp; else if (currentline &lt; 144)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DrawScanLine() ; <br>

&nbsp;&nbsp; }<br>

}

</p>

There is quite a bit there that I will give implementations to later so for now I'll just explain it. If the <b style="color:black;background-color:#99ff99">lcd</b> display
is enabled then we need to update the scanline counter by subtracting the last opcodes cycle time from it. If this makes
m_ScanlineCounter go negative then it is time to move onto the next scanline. Register 0xFF44 is the current scanline so
we increment this onto then next scanline. If the new scanline is 144 then this is the beginning of the vetical blank
interupt so we need to request this interupt (remember that the vblank interupt is bit 0). If you are unsure why this is
then re-read the <a href="http://www.codeslinger.co.uk/pages/projects/gameboy/interupts.html">interupts</a> chapter. If the current scanline is greater than 153 then it must be
reset to 0. However if the current scanline is less than 144 then it is one of the visible scanlines and needs to be rendered
to the screen. This will be explained in the chapter called <a href="http://www.codeslinger.co.uk/pages/projects/gameboy/graphics.html">Graphic Emulation</a>.
 The reason why
I access memory directly when writing to the current scanline address 
(0xFF44) rather than using WriteMemory is because
when the game tries to write to 0xFF44 it resets the current scaline to 
0, so we cannot use WriteMemory to increment the scanline
as it will always set it to 0. Speaking of which the following needs to 
be added to the WriteMemory function:

<p class="code">
// reset the current scanline if the game tries to write to it<br>
else if (address == 0xFF44)<br>
{<br>
&nbsp;&nbsp; m_Rom[address] = 0 ;<br>
}
</p>

<p></p>

<h3><b>Setting the <b style="color:black;background-color:#99ff99">LCD</b> Status:</b> </h3>
<p>
The memory address 0xFF41 holds the current status of the <b style="color:black;background-color:#99ff99">LCD</b>. The <b style="color:black;background-color:#99ff99">LCD</b> goes through 4 different modes. These are "V-Blank Period", "H-Blank Period", "Searching Sprite Attributes" and "Transferring
Data to <b style="color:black;background-color:#99ff99">LCD</b> Driver". Bit 1 and 0 of the <b style="color:black;background-color:#99ff99">lcd</b> status at address 0xFF41 reflects the current <b style="color:black;background-color:#99ff99">LCD</b> mode like so:

</p><p class="block">
00: H-Blank <br>
01: V-Blank <br>
10: Searching Sprites Atts <br>
11: Transfering Data to <b style="color:black;background-color:#99ff99">LCD</b> Driver
</p>

When starting a new scanline the <b style="color:black;background-color:#99ff99">lcd</b>
 status is set to 2, it then moves on to 3 and then to 0. It then goes 
back to and continues then pattern until
the v-blank period starts where it stays on mode 1. When the vblank 
period ends it goes back to 2 and continues this pattern over and over.
As previously mentioned it takes 456 clock cycles to draw one scanline 
before moving onto the next. This can be split down into different 
sections
which will represent the different modes. Mode 2 (Searching Sprites 
Atts) will take the first 80 of the 456 clock cycles. Mode 3 
(Transfering to <b style="color:black;background-color:#99ff99">LCD</b> 
Driver) will
take 172 clock cycles of the 456 and the remaining clock cycles of the 
456 is for Mode 0 (H-Blank). If this is confusing then please bare with 
me as it will all be come
clear when you see the code. <br><br>

When the <b style="color:black;background-color:#99ff99">LCD</b> status changes its mode to either Mode 0, 1 or 2 then this can cause an <b style="color:black;background-color:#99ff99">LCD</b> Interupt Request to happen. Bits 3, 4 and 5 of the <b style="color:black;background-color:#99ff99">LCD</b> Status register (0xFF41) are
interupt enabled flags (the same as the Interupt Enabled Register 0xFFFF, see <a href="http://www.codeslinger.co.uk/pages/projects/gameboy/interupts.html">interupts</a> chapter). These bits are set by the game not the emulator and
they represent the following:

<p class="block">
Bit 3: Mode 0 Interupt Enabled<br>
Bit 4: Mode 1 Interupt Enabled<br>
Bit 5: Mode 2 Interupt Enabled
</p>

So when the mode changes to 0,1 or 2 then if the corresponding bit 3,4,5 is set then an <b style="color:black;background-color:#99ff99">LCD</b> interupt is requested. This is only tested when the <b style="color:black;background-color:#99ff99">LCD</b> mode changes to 0,1 or 2 and not
the duration of these modes.<br><br>

One important part to emulate with the <b style="color:black;background-color:#99ff99">lcd</b> modes is when the <b style="color:black;background-color:#99ff99">lcd</b> is disabled the mode must be set to mode 1. If you dont do this then you will spend hours like I did wondering why
Mario2 wont play past the title screen. You also need to reset the m_ScanlineCounter and current scanline<br><br>

The last part of the <b style="color:black;background-color:#99ff99">LCD</b>
 status register (0xFF41) is the Coincidence flag. Basically Bit 2 of 
the status register is set to 1 if register (0xFF44) is the same value 
as (0xFF45) otherwise
it is set to 0. Bit 6 of the <b style="color:black;background-color:#99ff99">LCD</b> status register (0xFF44) is the same as the interupt enabled bits 3-5 but it isnt to do with the current <b style="color:black;background-color:#99ff99">lcd</b> mode it is to do with the bit 2 coincidence flag.
If the conicidence flag (bit 2) is set and the conincidence interupt enabled flag (bit 6) is set then an <b style="color:black;background-color:#99ff99">LCD</b>
 Interupt is requested. The conicidence flag means the current scanline 
(0xFF44) is the
same as a scanline the game is interested in (0xFF45). The reason why 
the game would be interested in the current scanline is to do special 
effects. So when 0xFF44 == 0xFF45 then an interupt can be
requested to let the game know that the values are the same.<br><br>

We now have enough information to put all this together and implement the SetLCDStatus function

<p class="code">

void Emulator::SetLCDStatus( ) <br>
{<br>
&nbsp;&nbsp; BYTE status = ReadMemory(0xFF41) ; <br>
&nbsp;&nbsp; if (false == IsLCDEnabled()) <br>
&nbsp;&nbsp; { <br>
&nbsp;&nbsp;&nbsp;&nbsp; // set the mode to 1 during <b style="color:black;background-color:#99ff99">lcd</b> disabled and reset scanline<br>
&nbsp;&nbsp;&nbsp;&nbsp; m_ScanlineCounter = 456 ; <br>
&nbsp;&nbsp;&nbsp;&nbsp; m_Rom[0xFF44] = 0 ; <br>
&nbsp;&nbsp;&nbsp;&nbsp; status &amp;= 252 ;<br>
&nbsp;&nbsp;&nbsp;&nbsp; status = BitSet(status, 0) ;<br>
&nbsp;&nbsp;&nbsp;&nbsp; WriteMemory(0xFF41,status) ;<br>
&nbsp;&nbsp;&nbsp;&nbsp; return ;<br>
&nbsp;&nbsp; }<br><br>

&nbsp;&nbsp; BYTE currentline = ReadMemory(0xFF44) ; <br>
&nbsp;&nbsp; BYTE currentmode = status &amp; 0x3 ;<br><br>

&nbsp;&nbsp; BYTE mode = 0 ;<br>
&nbsp;&nbsp; bool reqInt = false ; <br><br>

&nbsp;&nbsp; // in vblank so set mode to 1 <br>
&nbsp;&nbsp; if (currentline &gt;= 144)<br>
&nbsp;&nbsp; {
&nbsp;&nbsp;&nbsp;&nbsp; mode = 1;<br>
&nbsp;&nbsp;&nbsp;&nbsp; status = BitSet(status,0) ;<br>
&nbsp;&nbsp;&nbsp;&nbsp; status = BitReset(status,1) ;<br>
&nbsp;&nbsp;&nbsp;&nbsp; reqInt = TestBit(status,4) ; <br>
&nbsp;&nbsp; }<br>
&nbsp;&nbsp; else<br>
&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp; int mode2bounds = 456-80 ;<br>
&nbsp;&nbsp;&nbsp;&nbsp; int mode3bounds = mode2bounds - 172 ; <br><br>

&nbsp;&nbsp;&nbsp;&nbsp; // mode 2<br>
&nbsp;&nbsp;&nbsp;&nbsp; if (m_ScanlineCounter &gt;= mode2bounds)<br>
&nbsp;&nbsp;&nbsp;&nbsp; { <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mode = 2 ;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; status = BitSet(status,1) ;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; status = BitReset(status,0) ;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reqInt = TestBit(status,5) ; <br>
&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp;&nbsp; // mode 3<br>
&nbsp;&nbsp;&nbsp;&nbsp; else if(m_ScanlineCounter &gt;= mode3bounds)<br>
&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mode = 3 ;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; status = BitSet(status,1) ;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; status = BitSet(status,0) ;<br>
&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp;&nbsp; // mode 0<br>
&nbsp;&nbsp;&nbsp;&nbsp; else<br>
&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mode = 0;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; status = BitReset(status,1) ;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; status = BitReset(status,0) ;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reqInt = TestBit(status,3) ; <br>
&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp; }<br><br>

&nbsp;&nbsp; // just entered a new mode so request interupt<br>
&nbsp;&nbsp; if (reqInt &amp;&amp; (mode != currentmode))<br>
&nbsp;&nbsp;&nbsp;&nbsp; RequestInterupt(1) ;<br><br>

&nbsp;&nbsp; // check the conincidence flag<br>
&nbsp;&nbsp; if (ly == ReadMemory(0xFF45))<br>
&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp; status = BitSet(status,2) ;<br>
&nbsp;&nbsp;&nbsp;&nbsp; if (TestBit(status,6))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RequestInterupt(1) ;<br>
&nbsp;&nbsp; }<br>
&nbsp;&nbsp; else<br>
&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp; status = BitReset(status,2) ;<br>
&nbsp;&nbsp; }<br>
&nbsp;&nbsp; WriteMemory(0xFF41,status) ; <br>
}

</p>

Hopefully that all makes sense. If not re-read this section until it does. It took awhile for me to realise how the <b style="color:black;background-color:#99ff99">lcd</b> status works

<p></p>

<h3><b>The <b style="color:black;background-color:#99ff99">LCD</b> Control:</b> </h3>
<p>
The <b style="color:black;background-color:#99ff99">LCD</b> Control register (0xFF40) will be covered in detail in the chapter called <a href="http://www.codeslinger.co.uk/pages/projects/gameboy/graphics.html">Graphic Emulation</a> however
the above code uses the function IsLCDEnabled() a lot which I've yet to implement and this relies on the <b style="color:black;background-color:#99ff99">LCD</b> Control register. Bit 7 of this register
is responsible for enabling and disbaling the <b style="color:black;background-color:#99ff99">lcd</b> so we can implement IsLCDEnabled() like so:

</p><p class="code">
bool Emulator::IsLCDEnabled() const<br>
{<br>
&nbsp;&nbsp; return TestBit(ReadMemory(0xFF40),7) ;<br>
}
</p>

Thats it for the <b style="color:black;background-color:#99ff99">LCD</b> chapter onto <a href="http://www.codeslinger.co.uk/pages/projects/gameboy/dma.html">DMA Transfer</a>

<br><br>
<p>

<br><br>
</p>



</div>

<div id="sidebar">
<h3><b style="color:black;background-color:#a0ffff">Gameboy</b> Emulation:</h3>

<p>
<a class="sidelink" href="http://www.codeslinger.co.uk/pages/projects/gameboy/beginning.html">Getting Started</a><span class="hide"> | </span>
<a class="sidelink" href="http://www.codeslinger.co.uk/pages/projects/gameboy/hardware.html">The Hardware</a><span class="hide"> | </span>
<a class="sidelink" href="http://www.codeslinger.co.uk/pages/projects/gameboy/memory.html">Memory Control and Map</a><span class="hide"> | </span>
<a class="sidelink" href="http://www.codeslinger.co.uk/pages/projects/gameboy/banking.html">ROM and RAM Banking</a><span class="hide"> | </span>
<a class="sidelink" href="http://www.codeslinger.co.uk/pages/projects/gameboy/timers.html">The Timers</a><span class="hide"> | </span>
<a class="sidelink" href="http://www.codeslinger.co.uk/pages/projects/gameboy/interupts.html">Interupts</a><span class="hide"> | </span>
<a class="sidelink" href="http://www.codeslinger.co.uk/pages/projects/gameboy/lcd.html"><b style="color:black;background-color:#99ff99">LCD</b></a><span class="hide"> | </span>
<a class="sidelink" href="http://www.codeslinger.co.uk/pages/projects/gameboy/dma.html">DMA Transfer</a><span class="hide"> | </span>
<a class="sidelink" href="http://www.codeslinger.co.uk/pages/projects/gameboy/graphics.html">Graphic Emulation</a><span class="hide"> | </span>
<a class="sidelink" href="http://www.codeslinger.co.uk/pages/projects/gameboy/joypad.html">Joypad Emulation</a><span class="hide"> | </span>
<a class="sidelink" href="http://www.codeslinger.co.uk/pages/projects/gameboy/opcodes.html">Opcode Examples</a><span class="hide"> | </span>
<a class="sidelink" href="http://www.codeslinger.co.uk/pages/projects/gameboy/finished.html">Finished Product</a><span class="hide"> | </span>

</p>

</div>
    
<div id="footer">
Copyright © 2008 <b style="color:black;background-color:#ffff66">codeslinger</b>.co.uk
</div>

</div>




</div></body></html>